#undef  xuser
#include"chrono/now.hpp"
#include"chrono/now_utc.hpp"
#include"configure/platform.hpp"

#if xis_windows
    #include<windows.h>

    namespace mixc::chrono_now{
        inc::date now_t::date() {
            SYSTEMTIME t;
            GetLocalTime(& t);
            return inc::date(t.wYear, t.wMonth, t.wDay);
        }

        inc::datetime now_t::datetime() {
            SYSTEMTIME t;
            GetLocalTime(& t);
            return inc::datetime(t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, t.wMilliseconds);
        }

        inc::time now_t::time() {
            SYSTEMTIME t;
            GetLocalTime(& t);
            return inc::time(t.wHour, t.wMinute, t.wSecond, t.wMilliseconds);
        }
    }

    namespace mixc::chrono_now_utc{
        inc::date now_utc_t::date() {
            SYSTEMTIME t;
            GetSystemTime(& t);
            return inc::date(t.wYear, t.wMonth, t.wDay);
        }

        inc::datetime now_utc_t::datetime() {
            SYSTEMTIME t;
            GetSystemTime(& t);
            return inc::datetime(t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, t.wMilliseconds);
        }

        inc::time now_utc_t::time() {
            SYSTEMTIME t;
            GetSystemTime(& t);
            return inc::time(t.wHour, t.wMinute, t.wSecond, t.wMilliseconds);
        }
    }
#endif

#if xis_linux
    #include<time.h>
    #include<sys/time.h>

    namespace mixc::chrono_now{
        inline auto time_now(bool calc_zone){
            struct ::timezone z;
            struct ::timeval  t;
            gettimeofday(& t, & z);

            if (calc_zone){
                t.tv_sec -= z.tz_minuteswest * 60;
            }
            return t;
        }

        inline auto calc_date(timeval t){
            return 
                inc::date(1970, 1, 1) + 
                inc::day(t.tv_sec / (3600 * 24));
        }

        inline auto calc_time(timeval t){
            auto s    = t.tv_sec % 60;
            auto m    = t.tv_sec / 60 % 60;
            auto h    = t.tv_sec / 3600 % 24;
            return inc::time(h, m, s, t.tv_usec / 1000);
        }

        inc::date now_t::date() {
            return calc_date(
                time_now(true)
            );
        }

        inc::datetime now_t::datetime() {
            auto t = time_now(true);
            return inc::datetime(
                calc_date(t),
                calc_time(t)
            );
        }

        inc::time now_t::time() {
            return calc_time(
                time_now(true)
            );
        }
    }

    namespace mixc::chrono_now_utc{
        inc::date now_utc_t::date() {
            return mixc::chrono_now::calc_date(
                mixc::chrono_now::time_now(false)
            );
        }

        inc::datetime now_utc_t::datetime() {
            auto t = mixc::chrono_now::time_now(false);
            return inc::datetime(
                mixc::chrono_now::calc_date(t),
                mixc::chrono_now::calc_time(t)
            );
        }

        inc::time now_utc_t::time() {
            return mixc::chrono_now::calc_time(
                mixc::chrono_now::time_now(false)
            );
        }
    }

#elif xuse_mixc_rtos
    #undef  xuser
    #define xuser mixc::chrono_now_utc::inc
    #include"extern/rtos/cpu.hpp"
    #include"extern/rtos/c_cxx.hpp"
    #include"extern/rtos/trace.hpp"

    // TODO:
    // namespace mixc::chrono_now{}

    namespace mixc::chrono_now_utc{
        inc::date now_utc_t::date() {
            cdatetime value{};
            x_get_datetime(xmodify(value));
            return inc::date(
                value.year,
                value.month,
                value.day
            );
        }

        inc::datetime now_utc_t::datetime() {
            auto millisecond_a  = u64{};
            auto millisecond_b  = u64{};
            auto before         = cdatetime{};
            auto after          = cdatetime{};

            while(true){
                // 注意：
                // 这里不使用关中断包裹 x_get_datetime() 因为它可能是通过 I2C 读取数据的，
                // 关中断可能导致 I2C 通信异常
                // 
                // 这里使用关调度可能会导致死锁，假设 x_get_datetime() 是通过 I2C 读取数据，
                // 其他任务模块获取了 I2C 锁，此时锁还没释放，但切换到此任务执行，此任务关闭调度
                // 然后进入 x_get_datetime() 将获取不到 I2C 锁，但由于调度关闭，也无法执行之前获取到锁的任务
                // 所以会死锁

                // 这里为了解决时间分段读取导致错位的问题
                // 需要比对两次时间
                millisecond_a       = inc::g_trace.tick.total();
                x_get_datetime(xmodify(before));
                millisecond_b       = inc::g_trace.tick.total();
                x_get_datetime(xmodify(after));

                // 约定:
                // cdatetime 中所有的字段一共占用 64bit，不能多也不能少
                // 会存在将此结构转换成 u64 整数的操作
                // 
                // 这里是为了防止 datetime 部分和 millisecond 部分错位
                if (*u64p(&after) == *u64p(&before) and millisecond_a % 1000 <= millisecond_b % 1000){
                    break;
                }
            }

            return inc::datetime(
                after.year, after.month, after.day, after.hour, after.minute, after.second, u32(millisecond_b % 1000)
            );
        }

        inc::time now_utc_t::time() {
            return (inc::time)now_utc_t::datetime();
        }
    }
#endif
